#pragma once
#include <engine/MapRenderer.hpp>
#include <engine/TerrainMaterialManager.hpp>
#include <engine/MapFwd.hpp>
#include <engine/World.hpp>
#include <engine/WorldRenderer.hpp>
#include <engine/LightManager.hpp>
#include "TerrainDirector.hpp"

namespace he
{
	class Map;
	class CameraManager;
}

//! wxWidget for and Ogre rendering window
class wxOgre : public wxControl
{
	// Constants
private:
	//! Scroll offset.
	static unsigned char const SCROLL_OFFSET = 15;

	// Enums
private:
	//! Scrolling direction.
	enum ScrollDirection
	{
		SD_NONE,
		SD_LEFT,
		SD_RIGHT,
		SD_TOP,
		SD_BOTTOM
	};

	// Attributes
private:
	//! Rendering timer.
	wxTimer	mTimer;
	//! Log manager.
	std::unique_ptr<Ogre::LogManager> m_pLogManager;
	//! Local Ogre::Root pointer.
	std::auto_ptr<Ogre::Root> m_pRoot;
	//! Local Ogre::Viewport pointer.
	Ogre::Viewport* mViewPort;
	//! Local Ogre::SceneManager pointer.
	Ogre::SceneManager* mSceneMgr;
	//! Local Ogre::RenderWindow pointer.
	Ogre::RenderWindow* mRenderWindow;
	//! Debug overlay.
	Ogre::Overlay* m_pDebugOverlay; 
	//! Set to false until wxOgre is completely initialized.
	bool mIsInitialized;
	//! Ray scene query.
	Ogre::RaySceneQuery *m_pRaySceneQuery;
	//! GUI overlays.
	Ogre::OverlayElement* m_pGUICurrent, *m_pGUITriangles, *m_pGUIBatches;
	//! Position of mouse when button was hit.
	wxPoint m_MousePos;
	//! Timer for scrolling.
	wxTimer m_ScrollTimer;
	//! Scroll direction if any.
	ScrollDirection m_ScrollDir;
	//! World.
	std::unique_ptr<he::World> m_pWorld;
	//! World renderer.
	std::unique_ptr<he::WorldRenderer> m_pWorldRenderer;
	//! Last deep.
	long m_LastDeep;
	//! Last tile.
	he::TerrainTile const *m_pLastTile;
	//! Camera manager.
	std::unique_ptr<he::CameraManager> m_pCameraManager;
	//! Ratio for world unit width to viewport pixel size.
	float m_WorldWidthRatio;
	//! Ratio for world unit height to viewport pixel size.
	float m_WorldHeightRatio;
	//! Terrain director.
	TerrainDirector m_TerrainDirector;
	//! Highlight size.
	std::uint_least8_t m_HighlightSize;
	//! Light manager.
	std::unique_ptr<he::LightManager> m_pLightManager;

	// Operations
public:
	//! Get base mouse position.
	wxPoint const &get_base_mouse_pos() const;
	//! Move the camere.
	void move_camera(int X, int Z);
	//! Show tile outlines.
	Ogre::Ray get_world_from_screen(long X, long Y, he::MapRenderer::RayEntryContainer_t &Vectors);
	//! Enable/Disable wireframe.
	void show_wireframe(bool Show);
	//! Enable/disable noise.
	void enable_noise(bool Enable);
	//! Renders a single Ogre frame.
	void update();
	//! Get the scene manager.
	Ogre::SceneManager* getSceneManager() const;
	//! Get map renderer.
	he::MapRenderer &get_map_renderer();
	//! Get map.
	he::Map &get_map() const;
	//! Get terrain director.
	TerrainDirector &TerrainDirector();
private:
	//! Creates an ogre rendering window.
	void createOgreRenderWindow(Ogre::RenderSystem* renderSystem);
	/** Toggles the rendering timer on/off */
	void toggleTimerRendering();
	//! Update overlay stats.
	void update_stats();
	//! Setup resource.
	void setup_resources();
	//! Scroll the camera.
	void scroll();
	
	// Signal handlers
private:
	//! Windows resize handler.
	void OnSize(wxSizeEvent& event);
	//! Erase backgorund handler.
	void OnEraseBackground( wxEraseEvent& );
	//! Callback function to a timer "tick" event.
	void OnRenderTimer(wxTimerEvent& event);
	//! On mouse move.
	void on_mouse_move(wxMouseEvent &Event);
	//! Key down handler.
	void on_key_down(wxKeyEvent &Event);
	//! Mouse leave handler.
	void on_mouse_leave(wxMouseEvent &Event);
	//! Mouse enter handler.
	void on_mouse_enter(wxMouseEvent &Event);
	//! Mouse left button down handler.
	void on_mouse_lbutton_down(wxMouseEvent &Event);
	//! Timer handler.
	void on_scroll_timer(wxTimerEvent& Event);
	//! Set highlight tile size.
	void set_high_light_size(unsigned char Size);

	// Construction/Destruction
public:
	wxOgre (wxFrame* parent, Ogre::RenderSystem* renderSystem = 0);
	~wxOgre();

	// wx stuff
private:
	DECLARE_CLASS(wxOgre)
	DECLARE_EVENT_TABLE()
};

inline Ogre::SceneManager *wxOgre::getSceneManager() const
{
	return mSceneMgr;
}

inline he::MapRenderer &wxOgre::get_map_renderer()
{
	return m_pWorldRenderer->map_renderer();
}

inline he::Map &wxOgre::get_map() const
{
	return m_pWorld->map();
}

inline TerrainDirector &wxOgre::TerrainDirector()
{
	return m_TerrainDirector;
}